package com.example.hystrix.service.impl;

import com.example.common.api.CommonResult;
import com.example.hystrix.dto.UserDto;
import com.example.hystrix.service.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private RestTemplate restTemplate;

    private static final String userServiceUrl = "http://localhost:8201";

    @HystrixCommand(fallbackMethod = "getDefaultUser")
    @Override
    public CommonResult getUser(Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    public CommonResult getDefaultUser(@PathVariable Long id) {
        return CommonResult.success("服务已降级！");
    }

    /**
     * fallbackMethod：指定服务降级处理方法；
     * ignoreExceptions：忽略某些异常，不发生服务降级；
     * commandKey：命令名称，用于区分不同的命令；
     * groupKey：分组名称，Hystrix会根据不同的分组来统计命令的告警及仪表盘信息；
     * threadPoolKey：线程池名称，用于划分线程池。
     *
     * @param id
     * @return
     */
    @Override
    @HystrixCommand(fallbackMethod = "getDefaultUser",
            commandKey = "getUserCommand",
            groupKey = "getUserGroup",
            threadPoolKey = "getUserThreadPool")
    public CommonResult getUserCommand(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    /**
     * 空指针时不降级
     *
     * @param id
     * @return
     */
    @Override
    @HystrixCommand(fallbackMethod = "getDefaultUser2", ignoreExceptions = {NullPointerException.class})
    public CommonResult getUserException(Long id) {
        if (id == 1) {
            throw new IndexOutOfBoundsException();
        } else if (id == 2) {
            throw new NullPointerException();
        }
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    public CommonResult getDefaultUser2(@PathVariable Long id, Throwable e) {
        return CommonResult.success("异常降级！");
    }

    @Override
    @CacheResult(cacheKeyMethod = "getCacheKey")
    @HystrixCommand(fallbackMethod = "getDefaultUser", commandKey = "getUserCache")
    public CommonResult getUserCache(Long id) {
        // 通过接口调用发现之有一次日志打印，说明已经走了缓存
        log.info("getUserCache id:{}", id);
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    /**
     * 缓存方法
     *
     * @param id
     * @return
     */
    public String getCacheKey(Long id) {
        return String.valueOf(id);
    }

    /**
     * 请求合并
     *
     * @param id
     * @return
     */
    @Override
    @HystrixCollapser(batchMethod = "getUserByIds",collapserProperties = {
            @HystrixProperty(name = "timerDelayInMilliseconds", value = "100")
    })
    public Future<UserDto> getUserFuture(Long id) {
        return new AsyncResult<UserDto>(){
            @Override
            public UserDto invoke() {
//                CommonResult commonResult = restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
//                Map data = (Map) commonResult.getData();
//                UserDto user = BeanUtil.mapToBean(data, UserDto.class,true);
//                log.info("getUserById username:{}", user.getUsername());
                UserDto userDto = new UserDto();
                userDto.setNickName("李斯");
                return userDto;
            }

            @Override
            public UserDto get() throws UnsupportedOperationException {
                return invoke();
            }
        };
    }

    @HystrixCommand
    public List<UserDto> getUserByIds(List<Long> ids) {
        log.info("getUserByIds:{}", ids);
//        CommonResult commonResult = restTemplate.getForObject(userServiceUrl + "/user/getUserByIds?ids=1", CommonResult.class, CollUtil.join(ids,","));
//        return (List<UserDto>) commonResult.getData();
        UserDto userDto = new UserDto();
        userDto.setNickName("李斯");

        UserDto userDto1 = new UserDto();
        userDto1.setNickName("李斯2");
        List<UserDto> list = new ArrayList<>();
        list.add(userDto);
        list.add(userDto1);
        return list;
    }

}
